// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:analysis_server/protocol/protocol.dart';
import 'package:analysis_server/protocol/protocol_constants.dart';
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analysis_server/src/analytics/analytics_manager.dart';
import 'package:analysis_server/src/legacy_analysis_server.dart';
import 'package:analysis_server/src/server/crash_reporting_attachments.dart';
import 'package:analysis_server/src/server/error_notifier.dart';
import 'package:analysis_server/src/session_logger/session_logger.dart';
import 'package:analysis_server/src/socket_server.dart';
import 'package:analysis_server/src/utilities/mocks.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:test/test.dart';
import 'package:unified_analytics/unified_analytics.dart';

void main() {
  group('SocketServer', () {
    test(
      'createAnalysisServer_successful',
      SocketServerTest.createAnalysisServer_successful,
    );
    test(
      'createAnalysisServer_alreadyStarted',
      SocketServerTest.createAnalysisServer_alreadyStarted,
    );
  });
}

class SocketServerTest {
  static void createAnalysisServer_alreadyStarted() {
    var channel1 = MockServerChannel();
    var channel2 = MockServerChannel();
    var server = _createSocketServer(channel1);
    expect(
      channel1.notificationsReceived[0].event,
      serverNotificationConnected,
    );
    server.createAnalysisServer(channel2);
    channel1.expectMsgCount(notificationCount: 1);
    channel2.expectMsgCount(responseCount: 1);
    expect(channel2.responsesReceived[0].id, equals(''));
    expect(channel2.responsesReceived[0].error, isNotNull);
    expect(
      channel2.responsesReceived[0].error!.code,
      equals(RequestErrorCode.SERVER_ALREADY_STARTED),
    );
    channel2
        .simulateRequestFromClient(
          ServerShutdownParams().toRequest('0', clientUriConverter: null),
        )
        .then((Response response) {
          expect(response.id, equals('0'));
          var error = response.error!;
          expect(error.code, equals(RequestErrorCode.SERVER_ALREADY_STARTED));
          channel2.expectMsgCount(responseCount: 2);
        });
  }

  static Future<void> createAnalysisServer_successful() {
    var channel = MockServerChannel();
    _createSocketServer(channel);
    channel.expectMsgCount(notificationCount: 1);
    expect(channel.notificationsReceived[0].event, serverNotificationConnected);
    return channel
        .simulateRequestFromClient(
          ServerShutdownParams().toRequest('0', clientUriConverter: null),
        )
        .then((Response response) {
          expect(response.id, equals('0'));
          expect(response.error, isNull);
          channel.expectMsgCount(responseCount: 1, notificationCount: 1);
        });
  }

  static SocketServer _createSocketServer(MockServerChannel channel) {
    var errorNotifier = ErrorNotifier();
    var server = SocketServer(
      AnalysisServerOptions(),
      DartSdkManager(''),
      CrashReportingAttachmentsBuilder.empty,
      errorNotifier,
      SessionLogger(),
      null,
      null,
      AnalyticsManager(NoOpAnalytics()),
      null,
    );

    server.createAnalysisServer(channel);
    errorNotifier.server = server.analysisServer;
    AnalysisEngine.instance.instrumentationService = errorNotifier;

    return server;
  }
}

extension on MockServerChannel {
  void expectMsgCount({int responseCount = 0, int notificationCount = 0}) {
    expect(responsesReceived, hasLength(responseCount));
    expect(notificationsReceived, hasLength(notificationCount));
  }
}
